//
// Created by Tony on 2024/7/24.
//

#include "Instruction.h"
#include "../../common/Utils.h"
#include "../rt_code/Class.h"
#include <iomanip>
#include <memory>
#include <sstream>

namespace Runtime {

using std::make_shared;
using std::setw;
using std::stringstream;

std::string NoOperandsInstruction::toString() {
    stringstream ss;
    ss << std::left << setw(WIDTH_OP_NAME) << name();
    return ss.str();
}

std::string Index16Instruction::toString() {
    stringstream ss;
    ss << std::left << setw(WIDTH_OP_NAME) << name() << setw(WIDTH_UINT16) << mIndex;
    return ss.str();
}

std::string BranchInstruction::toString() {
    stringstream ss;
    ss << std::left << setw(WIDTH_OP_NAME) << name() << setw(WIDTH_UINT16) << mOffset;
    return ss.str();
}

RtTaggedValue CompareInstruction::cmp(RtTaggedValue a, RtTaggedValue b) {
    if (a.tag == RtValueTag::INT64) {
        if (b.tag == RtValueTag::INT64) {
            return RtTaggedValue(static_cast<int64_t>(COMPARE(a.value.int64, b.value.int64)));
        }
        if (b.tag == RtValueTag::FLT64) {
            return RtTaggedValue(static_cast<int64_t>(COMPARE(a.value.int64, b.value.flt64)));
        }
        // TODO: not support
    } else if (a.tag == RtValueTag::FLT64) {
        if (b.tag == RtValueTag::INT64) {
            return RtTaggedValue(static_cast<int64_t>(COMPARE(a.value.flt64, b.value.int64)));
        }
        if (b.tag == RtValueTag::FLT64) {
            return RtTaggedValue(static_cast<int64_t>(COMPARE(a.value.flt64, b.value.flt64)));
        }
        // TODO: not support
    }
    return {};
}

void initClass(RtData::Frame& frame, const shared_ptr<RtCode::Class>& clazz) {
    frame.revertNextPC();
    clazz->startInit();
    auto classInitMethod = clazz->getClassInitMethod();
    if (classInitMethod != nullptr) {
        auto stack = frame.getStack();
        auto newFrame = make_shared<RtData::Frame>(stack, classInitMethod);
        stack->push(newFrame);
    }
}

} // namespace Runtime
